#include "expressionvalidator.h"

#include "../types/multiset.h"
#include "../types/timedmultiset.h"
#include "../wfnet.h"

#include <bool.h>
#include <bstring.h>
#include <enumeration.h>
#include <type.h>
#include <typefactory.h>

#include <QtCore/QRegExp>
#include <QtCore/QStringList>

using namespace wfnet;

const ExpressionValidator::TokenMask ExpressionValidator::MT_VARIABLE_MASK =
    "\\{\\d+\\*([^_\\d\\W]+([a-zA-Z_]*\\d*)*)(@\\d+){0,1}\\}";
const ExpressionValidator::TokenMask ExpressionValidator::VARIABLE_MASK =
    "[^_\\d\\W]+([a-zA-Z_]*\\d*)*";
const ExpressionValidator::TokenMask ExpressionValidator::OPERATOR_MASK =
    "[^\\(\\)\\w\\s]+";
const ExpressionValidator::TokenMask ExpressionValidator::EXPRESSION_MASK =
    "\\(.*\\)";

class ExpressionValidator::ParseStep
{
public:
    ParseStep(const Expr& expr, bool subStep = false) :
        m_expr(expr), m_expressions(),
        m_operators(), m_variables(), m_values(),
        m_returnType(Type::INVALID_NAME), m_exprType(NONE),
        m_isSubStep(subStep)
    {}

    bool isEmpty() const
    { return m_expressions.empty() && m_operators.empty() &&
        m_variables.empty() && m_values.empty(); }

    bool isSubStep() const
    { return m_isSubStep; }

    bool isExpression(const ExpressionValidator::Token& token)
    {
        bool isExpression = false;

        for (int i = 0; i < m_expressions.size(); ++i)
        {
            if (m_expressions[i].first == token)
            {
                isExpression = true;
                break;
            }
        }

        return isExpression;
    }

    bool isVariable(const ExpressionValidator::Token& token)
    {
        bool isVariable = false;

        for (int i = 0; i < m_variables.size(); ++i)
        {
            if (m_variables[i].first == token)
            {
                isVariable = true;
                break;
            }
        }

        return isVariable;
    }

    bool isValue(const ExpressionValidator::Token& token)
    {
        bool isValue = false;

        for (int i = 0; i < m_values.size(); ++i)
        {
            if (m_values[i].first == token)
            {
                isValue = true;
                break;
            }
        }

        return isValue;
    }

    bool checkFlowCorectness(QSet<OperationName> boolOperations,
        QSet<OperationName> typeOperations) const
    {
        bool flowCorrect = true;
        uint lastTokenIndex = 0;

        lastTokenIndex = m_operators.size() > 0 ?
            (m_operators.last().second > lastTokenIndex ?
                 m_operators.last().second : lastTokenIndex) :
                    lastTokenIndex;
        lastTokenIndex = m_variables.size() > 0 ?
            (m_variables.last().second > lastTokenIndex ?
                 m_variables.last().second : lastTokenIndex) :
                    lastTokenIndex;
        lastTokenIndex = m_values.size() > 0 ?
            (m_values.last().second > lastTokenIndex ?
                 m_values.last().second : lastTokenIndex) :
                    lastTokenIndex;
        lastTokenIndex = m_expressions.size() > 0 ?
            (m_expressions.last().second > lastTokenIndex ?
                 m_expressions.last().second : lastTokenIndex) :
                    lastTokenIndex;

        if (m_operators.size() > 0)
        {
            // 0 for expecting non operator, 1 for expecting operator
            uint state = 0;

            uint _boolOperations = 0;
            uint _typeOperations = 0;

            for (uint currentIndex = 0; currentIndex <= lastTokenIndex;
                ++currentIndex)
            {
                if (state == 0)
                {
                    bool found = false;

                    for (int j = 0; j < m_variables.size(); ++j)
                    {
                        if (m_variables[j].second == currentIndex)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        for (int j = 0; j < m_values.size(); ++j)
                        {
                            if (m_values[j].second == currentIndex)
                            {
                                found = true;
                                break;
                            }
                        }
                    }

                    if (!found)
                    {
                        for (int j = 0; j < m_expressions.size(); ++j)
                        {
                            if (m_expressions[j].second == currentIndex)
                            {
                                found = true;
                                break;
                            }
                        }
                    }

                    if (!found)
                    {
                        flowCorrect = false;
                        break;
                    }

                    state = 1;
                }
                else
                {
                    bool found = false;

                    for (int j = 0; j < m_operators.size(); ++j)
                    {
                        // not initialized yet
                        if (_boolOperations == 0 || _typeOperations == 0)
                        {
                            if (boolOperations.contains(m_operators[j].first))
                            {
                                _boolOperations = 1; // actually 1+
                            }
                            else
                            {
                                _typeOperations = 1; // actually 1+
                            }
                        }

                        if (m_operators[j].second == currentIndex)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        flowCorrect = false;
                        break;
                    }

                    state = 0;
                }
            }

            flowCorrect = flowCorrect && ((_boolOperations > 0 &&
                _typeOperations == 0) || (_boolOperations == 0 &&
                _typeOperations > 0));
        }
        else
        {
            flowCorrect = (m_expressions.size() + m_variables.size() +
                m_values.size()) == 1;
        }

        return flowCorrect;
    }

    ExpressionValidator::Token getLeftOperand(uint operatorIndex) const
    {
        ExpressionValidator::Token operand;
        bool skip = false;

        for (int i = 0; i < m_variables.size(); ++i)
        {
            if (m_variables[i].second == (operatorIndex - 1))
            {
                operand = m_variables[i].first;
                skip = true;
                break;
            }
        }

        if (!skip)
        {
            for (int i = 0; i < m_expressions.size(); ++i)
            {
                if (m_expressions[i].second == (operatorIndex - 1))
                {
                    operand = m_expressions[i].first;
                    skip = true;
                    break;
                }
            }
        }

        if (!skip)
        {
            for (int i = 0; i < m_values.size(); ++i)
            {
                if (m_values[i].second == (operatorIndex - 1))
                {
                    operand = m_values[i].first;
                    break;
                }
            }
        }

        return operand;
    }

    ExpressionValidator::Token getRightOperand(uint operatorIndex) const
    {
        ExpressionValidator::Token operand;
        bool skip = false;

        for (int i = 0; i < m_values.size(); ++i)
        {
            if (m_values[i].second == (operatorIndex + 1))
            {
                operand = m_values[i].first;
                break;
            }
        }

        if (!skip)
        {
            for (int i = 0; i < m_variables.size(); ++i)
            {
                if (m_variables[i].second == (operatorIndex + 1))
                {
                    operand = m_variables[i].first;
                    skip = true;
                    break;
                }
            }
        }

        if (!skip)
        {
            for (int i = 0; i < m_expressions.size(); ++i)
            {
                if (m_expressions[i].second == (operatorIndex + 1))
                {
                    operand = m_expressions[i].first;
                    skip = true;
                    break;
                }
            }
        }

        return operand;
    }

public:
    Expr m_expr;
    Expr m_systemExpr;

    ExpressionValidator::TokenList m_expressions;
    ExpressionValidator::TokenList m_operators;
    ExpressionValidator::TokenList m_variables;
    ExpressionValidator::TokenList m_values;

    TypeName m_returnType;
    ExpressionType m_exprType;

    bool m_isSubStep;
};

ExpressionValidator* expressionValidator = 0;

ExpressionValidator* ExpressionValidator::getInstance()
{
    if (expressionValidator == 0)
    {
        expressionValidator = new ExpressionValidator();
    }

    return expressionValidator;
}

void ExpressionValidator::destroy()
{
    delete expressionValidator;
    expressionValidator = 0;
}

bool ExpressionValidator::validate(const Expr& expr, const TypeName& context,
    bool timed, WfNet* net)
{
    clean();

    bool valid = true;

    const QSet<VariableName> regVariables = net->registeredVariables();

    ParseStep* baseStep = new ParseStep(expr);
    const bool parsed = parseTokens(expr, baseStep);

    if (!parsed)
    {
        delete baseStep;
        valid = false;
    }
    else
    {     
        QSet<ParseStep* > currentLevel;
        currentLevel << baseStep;

        while (currentLevel.size() != 0)
        {          
            QSet<ParseStep* > nextLevel;

            foreach (ParseStep* step, currentLevel)
            {
                m_steps.push(step);

                // check if it contains only variables registered for the net
                if (!checkVariables(step, timed, net))
                {
                    valid = false;
                    break;
                }

                if (!unfoldExpressions(step, nextLevel))
                {
                    valid = false;
                    break;
                }                
            }

            currentLevel = nextLevel;
        }
    }

    if (valid)
    {
        for (int i = m_steps.size() - 1; i >= 0; --i)
        {
            ParseStep* step = m_steps[i];
            if (!parseOperations(step, context, timed, net))
            {
                valid = false;

                break;
            }

            m_exprType |= step->m_exprType;
        }

        makeSystemExpression(baseStep->m_systemExpr);
        m_expressionReturnType = baseStep->m_returnType;
    }
    else
    {
        clean();
    }

    for (int i = 0; i < m_steps.size(); ++i)
    {
        ParseStep* step = m_steps.at(i);
        delete step;
        step = 0;
    }

    m_steps.clear();
    m_exprMapping.clear();

    return valid;
}

UserVariables ExpressionValidator::getFoundVariables() const
{
    return m_lastFoundVariables;
}

SystemVariables ExpressionValidator::getSystemVariables() const
{
    return m_lastSystemVariables;
}

Expr ExpressionValidator::getSystemExpression() const
{
    return m_systemExpression;
}

TypeName ExpressionValidator::getReturnType() const
{
    return m_expressionReturnType;
}

uint ExpressionValidator::getExprType() const
{
    return m_exprType;
}

void ExpressionValidator::registerKeywordMasks(const QSet<ValueKeywordMask>& masks)
{
    m_keywordMasks = masks;

    makeMultisetKeywords();
}

 void ExpressionValidator::clearKeywordMasks()
 {
     m_keywordMasks.clear();
     m_multisetKeywordMasks.clear();
 }

ExpressionValidator::ExpressionValidator() :
    m_systemVariableChar('a'),
    m_systemExpression(),
    m_exprType(NONE),
    m_expressionReturnType(Type::INVALID_NAME),
    m_steps(),
    m_exprMapping(),
    m_keywordMasks(),
    m_multisetKeywordMasks(),
    m_boolOperations(),
    m_typeOperations(),
    m_operationToMethodMapping(),
    m_lastFoundVariables(),
    m_lastSystemVariables(),
    m_determinedValueTypes()
{
    m_boolOperations << OPERATION_EQUALTO << OPERATION_NEQUALTO <<
        OPERATION_LESS_THAN << OPERATION_GREATER_THAN << OPERATION_LEQUALTO <<
        OPERATION_GEQUALTO << OPERATION_LAND << OPERATION_LOR <<
        OPERATION_LNOT;
    m_typeOperations << OPERATION_ADDITION << OPERATION_SUBSTRACTION <<
        OPERATION_INCREMENT << OPERATION_DECREMENT <<
        OPERATION_MULTIPLICATION << OPERATION_DIVISION << OPERATION_MODULO;

    m_operationToMethodMapping[OPERATION_EQUALTO] = "equal";
    m_operationToMethodMapping[OPERATION_NEQUALTO] = "notEqual";
    m_operationToMethodMapping[OPERATION_LESS_THAN] = "lessThan";
    m_operationToMethodMapping[OPERATION_GREATER_THAN] = "greaterThan";
    m_operationToMethodMapping[OPERATION_LEQUALTO] = "lessOrEqual";
    m_operationToMethodMapping[OPERATION_GEQUALTO] = "greaterOrEqual";
    m_operationToMethodMapping[OPERATION_LAND] = "and";
    m_operationToMethodMapping[OPERATION_LOR] = "or";
    m_operationToMethodMapping[OPERATION_LNOT] = "not";
    m_operationToMethodMapping[OPERATION_ADDITION] = "add";
    m_operationToMethodMapping[OPERATION_SUBSTRACTION] = "sub";
    m_operationToMethodMapping[OPERATION_INCREMENT] = "inc";
    m_operationToMethodMapping[OPERATION_DECREMENT] = "dec";
    m_operationToMethodMapping[OPERATION_MULTIPLICATION] = "mul";
    m_operationToMethodMapping[OPERATION_DIVISION] = "div";
    m_operationToMethodMapping[OPERATION_MODULO] = "mod";
}

ExpressionValidator::~ExpressionValidator()
{

}

bool ExpressionValidator::parseTokens(const Expr& expr, ParseStep* step)
{
    // TODO: parseTokens doesn't support unary operators

    QStringList tokens;

    uint inParenthesis = 0;
    uint inCurlyBraces = 0;
    int pos = 0;

    const Expr _expr = expr.simplified();

    if (_expr.contains(' '))
    {
        const int length = _expr.length();
        for (int i = 0; i < length; ++i)
        {
            if (_expr[i].isSpace() && inParenthesis == 0 &&
                inCurlyBraces == 0)
            {
                tokens.append(_expr.mid(pos, i - pos));
                pos = i + 1;
            }

            if (_expr[i] == '(')
            {
                ++inParenthesis;
            }

            if (_expr[i] == ')')
            {
                --inParenthesis;
            }

            if (_expr[i] == '{')
            {
                ++inCurlyBraces;
            }

            if (_expr[i] == '}')
            {
                --inCurlyBraces;
            }
        }

        if (tokens.size() > 0 && inParenthesis == 0)
        {
            tokens.append(_expr.right(length - pos));
        }

        if (tokens.size() == 0 && inParenthesis == 0)
        {
            tokens.append(_expr);
        }
    }
    else if (_expr.length() > 0)
    {
       tokens.append(_expr);
    }
    else
    {
        // do nothing
    }

    if (tokens.size() != 0 && inParenthesis == 0 && inCurlyBraces == 0)
    {
        QRegExp regex;

        uint i = 0;
        foreach (const Token& token, tokens)
        {
            bool skip = false;

            /********
              VALUE
            *********/
            foreach (const ValueKeywordMask& keyword, m_keywordMasks)
            {
                regex.setPattern(keyword);

                if (regex.exactMatch(token))
                {
                    step->m_values.append(QPair<Token, uint>(token, i));

                    skip = true;
                    break;
                }
            }

            /***********
              VARIABLE
            ************/
            if (!skip)
            {
                regex.setPattern(VARIABLE_MASK);

                if (regex.exactMatch(token))
                {
                    step->m_variables.append(QPair<Token, uint>(token, i));
                    skip = true;
                }

                regex.setPattern(MT_VARIABLE_MASK);

                if (regex.exactMatch(token))
                {
                    step->m_variables.append(QPair<Token, uint>(token, i));
                    skip = true;
                }
            }

            /***********
              OPERATOR
            ************/
            if (!skip)
            {
                regex.setPattern(OPERATOR_MASK);

                if (regex.exactMatch(token))
                {
                    step->m_operators.append(QPair<Token, uint>(token, i));
                    skip = true;
                }
            }

            /*************
              EXPRESSION
            **************/
            if (!skip)
            {
                /* for expressions (all expressions has to be
                surrounded by parenthesis*/
                regex.setPattern(EXPRESSION_MASK);

                if (regex.exactMatch(token))
                {
                    step->m_expressions.append(QPair<Token, uint>(token, i));
                }
            }

            ++i;
        }
    }

    return step->checkFlowCorectness(m_boolOperations, m_typeOperations)
        && !step->isEmpty();
}

bool ExpressionValidator::parseOperations(ParseStep* step,
    const TypeName& context, bool timed, WfNet* net)
{
    QStringList systemExprList;

    step->m_exprType = step->m_operators.size() > 0 ?
        (step->m_variables.size() > 1 ? COMPLEX_VAR_VAR : COMPLEX_VAR_VAL) :
        (step->m_values.size() > 0 ? SIMPLE_VAL_ONLY : SIMPLE_VAR_ONLY);

    if (step->m_operators.size() == 0 && step->m_expressions.size() == 0)
    {
        if (step->m_variables.size() != 0)
        {
            step->m_returnType = determineVariableType(
                step->m_variables[0].first, context, timed, net)->name();
        }
        else
        {
            const Token value = step->m_values[0].first;

            const Type* type = determineValueType(value, context, timed, net);
            step->m_returnType = type != 0 ? type->name() : Type::INVALID_NAME;
        }

        step->m_systemExpr = step->m_expr;
    }
    else if (step->m_operators.size() == 0 && step->m_expressions.size() > 0)
    {
        // in this case, the m_expressions size should be 1
        const Expr expr = step->m_expressions[0].first;

        if (m_exprMapping.contains(expr))
        {
            step->m_returnType = m_exprMapping[expr].first;
            step->m_systemExpr = m_exprMapping[expr].second;
        }
    }
    else
    {        
        for (int i = 0; i < step->m_operators.size(); ++i)
        {
            const uint operatorIndex = step->m_operators[i].second;

            Token leftOperand = step->getLeftOperand(operatorIndex);
            Token rightOperand = step->getRightOperand(operatorIndex);

            // determine leftOpType and if it supports particular operator
            const Type* leftOpType = 0;
            const Type* rightOpType = 0;

            const OperationName operation = step->m_operators[i].first;

            if (step->isVariable(leftOperand))
            {
                const Type* type = determineVariableType(leftOperand, context,
                    timed, net);

                if (type != 0 && type->supports(operation))
                {
                    leftOpType = type;
                }
            }
            else if (step->isExpression(leftOperand))
            {
                if (m_exprMapping.contains(leftOperand))
                {
                    const TypeName name = m_exprMapping[leftOperand].first;

                    leftOpType =
                        TypeFactory::getInstance()->getTypeInstance(name);

                    leftOperand = m_exprMapping[leftOperand].second;
                }
            }
            else // value
            {
                const Type* type = determineValueType(leftOperand, context,
                    timed, net);

                if (type != 0 && type->supports(operation))
                {
                    leftOpType = type;
                }
            }

            if (leftOpType != 0)
            {
                // determine rightOpType and if it supports particular operator

                if (step->isValue(rightOperand))
                {
                    const Type* type = determineValueType(rightOperand,
                        context, timed, net);
                    const TypeName name = type != 0 ? type->name() :
                        Type::INVALID_NAME;

                    const bool matchesRightOp = type != 0 ? type->matches(
                        leftOpType->rightOperatorType(operation)) : false;

                    if (leftOpType->matches(name) || matchesRightOp)
                    {
                        rightOpType = type;
                    }
                }
                else if (step->isVariable(rightOperand))
                {
                    const Type* type = determineVariableType(rightOperand,
                        context, timed, net);
                    const TypeName name = type != 0 ? type->name() :
                        Type::INVALID_NAME;

                    const bool matchesRightOp = type != 0 ? type->matches(
                        leftOpType->rightOperatorType(operation)) : false;

                    if (leftOpType->matches(name) || matchesRightOp)
                    {
                        rightOpType = type;
                    }
                }
                else // expression
                {
                    if (m_exprMapping.contains(rightOperand))
                    {
                        const TypeName name = m_exprMapping[
                            rightOperand].first;

                        if (leftOpType->matches(name))
                        {
                            rightOpType = TypeFactory::getInstance()->
                                getTypeInstance(name);
                        }

                        rightOperand = m_exprMapping[rightOperand].second;
                    }
                }

                if (rightOpType != 0)
                {
                    const TypeName retType = leftOpType->operationReturnType(
                        operation);

                    if (retType == Multiset::NAME ||
                        retType == TimedMultiset::NAME)
                    {
                        step->m_returnType = leftOpType->name();
                    }
                    else
                    {
                        const Type* colorSet = convertToColoSet(retType,
                            context, timed, net);

                        step->m_returnType = colorSet != 0 ? colorSet->name()
                            : Type::INVALID_NAME;
                    }
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }

            Expr systemExpression = step->isSubStep() ? "%1.%2(%3)" :
                "%1.%2(%3);";
            const OperationMethod method = m_operationToMethodMapping[
                step->m_operators[i].first];

            systemExprList.append(systemExpression.arg(leftOperand)
                .arg(method).arg(rightOperand));
        }
    }

    for (int i = systemExprList.size() - 1; i >= 0; --i)
    {
        step->m_systemExpr += systemExprList.at(i);
    }

    if (step->isSubStep())
    {
        saveSubExprResult(step);
    }

    return step->m_returnType != Type::INVALID_NAME;
}

bool ExpressionValidator::unfoldExpressions(ParseStep* currentStep,
    QSet<ParseStep* >& nextLevel)
{
    bool parsed = true;

    for (int i = 0; i < currentStep->m_expressions.size(); ++i)
    {
        const QPair<Token, uint>& expr = currentStep->m_expressions[i];

        Expr _expr = expr.first;
        _expr = _expr.mid(1, _expr.length() - 2);

        ParseStep* subStep = new ParseStep(expr.first, true);

        const bool parsed = parseTokens(_expr, subStep);

        if (parsed)
        {
            nextLevel << subStep;
        }
        else
        {
            delete subStep;

            foreach (ParseStep* step, nextLevel)
            {
                delete step;
            }

            nextLevel.clear();

            break;
        }
    }

    return parsed;
}

bool ExpressionValidator::checkVariables(ParseStep* step, bool timed,
    WfNet* net) const
{
    bool check = true;

    const QSet<VariableName> registeredVariables =
        net->registeredVariables();

    for (int i = 0; i < step->m_variables.size(); ++i)
    {
        const QPair<Token, uint>& var = step->m_variables[i];

        VariableName name = var.first;
        if (name.startsWith("{") && name.endsWith("}"))
        {
            QRegExp regex("([a-zA-Z\\_]+\\d*)");
            const int index = regex.indexIn(name);
            name = index != -1 ? regex.cap() : "";
        }

        if (!registeredVariables.contains(name) ||
            net->isVariableTimed(name) != timed)
        {
            check = false;
            break;
        }
    }

    return check;
}

const Type* ExpressionValidator::determineValueType(
    const TypeValue& value, const TypeName& context, bool timed, WfNet* net)
{
    const Type* type = 0;

    const QSet<ColorSetName> regColorSets =
        net->registeredColorSets();

    if (value.startsWith("{") && value.endsWith("}"))
    {
        foreach (const ColorSetName& name, regColorSets)
        {
            const TypeName multisetName = value.contains("@") ?
                TimedMultiset::constructName(name) :
                    Multiset::constructName(name);
            const TypeName contextMSName = value.contains("@") ?
                TimedMultiset::constructName(context) :
                    Multiset::constructName(context);

            const Type* _type =
                TypeFactory::getInstance()->getTypeInstance(multisetName);

            // _type can be NULL in this instance, because of timed/untimed
            if (_type != 0 && _type->canConvert(value) &&
                _type->name() == contextMSName &&
                value.contains("@") == timed)
            {
                type = _type;
                break;
            }
        }
    }
    else
    {
        const Type* preferredType = 0;
        const Type* foundType = 0;

        foreach (const ColorSetName& name, regColorSets)
        {
            const ColorSet* _type = dynamic_cast<const ColorSet* >(
                TypeFactory::getInstance()->getTypeInstance(name));

            Q_ASSERT(_type != 0);

            if (_type->canConvert(value) && _type->name() == context &&
                _type->isTimed() == timed)
            {
                preferredType = _type;
                break;
            }
            if (_type->canConvert(value) && _type->isTimed() == timed)
            {
                foundType = _type;
            }
        }

        type = preferredType != 0 ? preferredType : foundType;
    }

    if (type != 0 && !m_determinedValueTypes.contains(value))
    {
        m_determinedValueTypes[value] = QPair<TypeName, VariableName>(
            type->name(), "");
    }

    return type;
}

const Type* ExpressionValidator::determineVariableType(
    const VariableName& variable, const TypeName& context, bool timed,
    WfNet* net)
{
    const Type* type = 0;

    const QSet<ColorSetName> regColorSets =
        net->registeredColorSets();

    if (variable.startsWith("{") && variable.endsWith("}"))
    {
        VariableName name = variable;
        QRegExp regex("([a-zA-Z\\_]+\\d*)");
        const int index = regex.indexIn(name);
        name = index != -1 ? regex.cap() : "";

        ColorSetName variableName = net->variableType(name);

        const TypeName multisetName = variable.contains("@") ?
            TimedMultiset::constructName(variableName) :
                Multiset::constructName(variableName);

        const Type* _type =
            TypeFactory::getInstance()->getTypeInstance(multisetName);

        // _type can be NULL in this instance, because of timed/untimed
        if (_type != 0 && !m_determinedValueTypes.contains(variable) &&
                variable.contains("@") == timed)
        {
            m_determinedValueTypes[variable] = QPair<TypeName, VariableName>(
                _type->name(), name);
        }

        type = _type;
    }
    else
    {
        ColorSetName variableName = net->variableType(variable);

        foreach (const ColorSetName& name, regColorSets)
        {
            const ColorSet* _type = dynamic_cast<const ColorSet* >(
                TypeFactory::getInstance()->getTypeInstance(name));

            Q_ASSERT(_type != 0);

            if (_type->matches(variableName) && _type->name() == context &&
                _type->isTimed() == timed)
            {
                type = _type;

                if (!m_lastFoundVariables.contains(variable))
                {
                    m_lastFoundVariables[variable] = name;
                }

                break;
            }
        }
    }

    return type;
}

const Type* ExpressionValidator::convertToColoSet(const TypeName& name,
    const TypeName& context, bool timed, WfNet* net)
{
    const Type* type = 0;

    const QSet<ColorSetName> regColorSets =
        net->registeredColorSets();

    foreach (const ColorSetName& _name, regColorSets)
    {
        const ColorSet* _type = dynamic_cast<const ColorSet* >(
            TypeFactory::getInstance()->getTypeInstance(_name));

        Q_ASSERT(_type != 0);

        if (_type->matches(name) && _type->isTimed() == timed)
        {
            if (!_type->matches(Bool::NAME) && _type->name() == context)
            {
                type = _type;
                break;
            }
            else
            {
                type = _type;
                break;
            }
        }
    }

    return type;
}

void ExpressionValidator::saveSubExprResult(ParseStep* step)
{
    Expr stepExpr = step->m_expr;
    if (!m_exprMapping.contains(stepExpr))
    {
        m_exprMapping[stepExpr] = QPair<TypeName, Expr>(
            step->m_returnType, step->m_systemExpr);
    }
}

void ExpressionValidator::makeSystemExpression(const Expr& expr)
{
    m_systemExpression = expr;

    QSet<ValueKeywordMask> multisetMasks = m_multisetKeywordMasks;
    multisetMasks << MT_VARIABLE_MASK;

    foreach (const ValueKeywordMask& mask, multisetMasks)
    {
        changeValuesToSystemVariables(m_systemExpression, mask);
    }

    foreach (const ValueKeywordMask& mask, m_keywordMasks)
    {
        changeValuesToSystemVariables(m_systemExpression, mask);
    }
}

void ExpressionValidator::changeValuesToSystemVariables(const Expr& expr,
        const ValueKeywordMask& mask)
{
    QRegExp regex(mask);
    QStringList list;
    int pos = 0;

    while ((pos = regex.indexIn(m_systemExpression, pos)) != -1) {
        list << regex.cap(0);
        pos += regex.matchedLength();
    }

    foreach (const TypeValue& token, list)
    {
        int index = m_systemExpression.indexOf(token);

        if (index != -1)
        {
            QString variableName("_%1");
            variableName = variableName.arg(m_systemVariableChar);

            const QPair<TypeName, VariableName>& type =
                m_determinedValueTypes[token];

            m_lastSystemVariables[variableName] =
                SystemVariable(type.first, token,
                    !type.second.isEmpty(), type.second);

            m_systemExpression.replace(index, token.length(),
                variableName);

            ++m_systemVariableChar;
        }
    }
}

void ExpressionValidator::makeMultisetKeywords()
{
    m_keywordMasks.remove(Multiset::KEYWORD_MASK);

    QString mask = Multiset::KEYWORD_MASK;

    foreach (const ValueKeywordMask& keyword, m_keywordMasks)
    {
        m_multisetKeywordMasks << mask.arg(keyword);
    }

    foreach (const ValueKeywordMask& keyword, m_multisetKeywordMasks)
    {
        m_keywordMasks << keyword;
    }
}

void ExpressionValidator::clean()
{
    m_lastFoundVariables.clear();
    m_lastSystemVariables.clear();

    m_determinedValueTypes.clear();

    m_systemVariableChar = 'a';
    m_systemExpression = "";
    m_exprType = NONE;
    m_expressionReturnType = Type::INVALID_NAME;
}
